#include "RichTextChatLog.h"
#include "../StdUserInterfaceModule/Icons.h"
#include "../../core/Impp.h"
#include <wx/regex.h>

namespace Impp
{

IMPLEMENT_DYNAMIC_CLASS(StdRichTextChatLogModule, iChatLogFactory)

RichTextChatLog::RichTextChatLog() :
	buddy(NULL),
	log(NULL),
	smileyCount(0),
	smileys(NULL),
	locks(0)
{
	ModuleManager* modules = Impp::exemplar()->getModuleManager();
	modules->loadAndInit(MODULE_INTERFACE_SMILEY_THEME_MANAGER);

	iModule* module = modules->getModuleByInterface(MODULE_INTERFACE_SMILEY_THEME_MANAGER);
	if(module != NULL){
		if(iSmileyThemeManager* sm = dynamic_cast<iSmileyThemeManager*>(module)){
			smileys = sm;
		}else{
			wxASSERT(sm != NULL);
		}
	}else{
		wxLogError(wxT("Coudn't create RichTextChatLog, no SmileyThemeManager found"));
		wxASSERT(module != NULL);
	}

	iUserInterface* ui = Impp::exemplar()->getModuleManager()->getUserInterfaceModule();
	if(ui != NULL){
		iIcons* icons = ui->getIcons();
		msgNormal = icons->getBitmap(wxT("icons/msg/msg_normal.png"));
		msgError = icons->getBitmap(wxT("icons/msg/msg_failed.png"));
		msgUnknown = icons->getBitmap(wxT("icons/msg/msg_unknown.png"));
	}else{
		wxLogError(wxT("RichTextChatLog: no Userinterface found!"));
	}



}

RichTextChatLog::~RichTextChatLog()
{
}

void RichTextChatLog::create(Buddy* buddy, wxWindow* parent, int id){
	this->buddy=buddy;
	log = new wxRichTextCtrl(parent,id,wxEmptyString,wxDefaultPosition,wxDefaultSize,wxTE_READONLY|wxRE_MULTILINE|wxTE_AUTO_URL);
	log->SetEditable(false);
	log->Connect(wxEVT_IDLE, wxIdleEventHandler(RichTextChatLog::onIdleEvent),NULL, this);
}

void RichTextChatLog::onIdleEvent(wxIdleEvent & event){
	if(actions.size() == 0){
		return;
	}
	LogAction* action = actions[0];
	if(LogMessageAction* lm = dynamic_cast<LogMessageAction*>(action)){
		doWriteMessage(lm);
	}else if(LogStatusMessageAction* lsm = dynamic_cast<LogStatusMessageAction*>(action)){
		doWriteStatusMessage(lsm);
	}else if(LogMarkMessageAction* lmm = dynamic_cast<LogMarkMessageAction*>(action)){
		doMarkMessage(lmm);
	}else if(LogScollToEndAction* lmm = dynamic_cast<LogScollToEndAction*>(action)){
		doScrollToEnd();
	}

	actions.erase(actions.begin());
	delete action;
	event.Skip();
}

void RichTextChatLog::freeze(){
	if(locks == 0){
		log->Freeze();
	}
	locks++;
}

void RichTextChatLog::thaw(){
	if(locks == 1){
		log->Thaw();
	}
	locks--;
}


void RichTextChatLog::doWriteStatusMessage(LogStatusMessageAction* action){
	freeze();

	if(!log->IsEmpty()){
		log->AppendText(wxT("\n"));
	}

	wxColor color = wxColor(80,80,80);

	log->SetDefaultStyle(wxTextAttr(color));

	iUserInterface* ui = Impp::exemplar()->getModuleManager()->getUserInterfaceModule();
	if(ui != NULL){
		log->WriteImage(ui->getIcons()->getStatusIcon(action->status));
	}
	log->WriteText(wxT(" ("));
	log->WriteText(wxDateTime::Now().FormatTime());
	log->WriteText(wxT(") "));
	log->WriteText(buddy->getName());
	log->WriteText(wxT(" is "));
	log->WriteText(statusToString(action->status));

	if(!action->statusMsg.IsEmpty()){
		log->WriteText(wxT(": "));
		writeParsedText(action->statusMsg);
	}

	log->SetDefaultStyle(wxTextAttr(*wxBLACK));
	thaw();
}
void RichTextChatLog::doWriteMessage(LogMessageAction* action){
	freeze();

	if(!log->IsEmpty()){
		log->AppendText(wxT("\n"));
	}

	if(action->id != -1){
		//Status Marker
		int pos = log->GetLastPosition();


		ActionManager* acManager = Impp::exemplar()->getActionManager();
		acManager->setActionData(action->id,wxT("log_pos"),pos);
		acManager->lockAction(action->id);
	}




	if(action->in){
		log->WriteImage(msgNormal);
		log->SetDefaultStyle(wxTextAttr(*wxBLUE));
	}else{
		if(action->isHistory){
			log->WriteImage(msgNormal);
		}else{
			log->WriteImage(msgUnknown);
		}

		log->SetDefaultStyle(wxTextAttr(*wxRED));
	}

	log->WriteText(wxT(" ("));
	log->WriteText(action->time.FormatTime());
	log->WriteText(wxT(") "));
	log->WriteText(action->sender->getName());
	log->WriteText(wxT(": "));

	log->SetDefaultStyle(wxTextAttr(*wxBLACK));
	writeParsedText(action->msg);
	thaw();
}
void RichTextChatLog::doMarkMessage(LogMarkMessageAction* action){
	ActionManager* acManager = Impp::exemplar()->getActionManager();
	int pos = acManager->getActionData(action->event->getId(),wxT("log_pos"));
	acManager->unLockAction(action->event->getId());

	if(action->event->getState()==MESSAGE_STATE_SERVER_REPLAY){

		if(pos != -1){
			log->Delete(wxRichTextRange(pos,pos+1));
			log->WriteImage(msgNormal);
			log->SetInsertionPointEnd();
		}
	}

	if(action->event->getState()==MESSAGE_STATE_FAILED){
		if(pos != -1){
			log->Delete(wxRichTextRange(pos,pos+1));
			log->WriteImage(msgError);
			log->SetInsertionPointEnd();
		}
		log->Freeze();
		log->SetDefaultStyle(wxTextAttr(*wxRED));
		log->WriteText(wxT("\n"));
		log->WriteText(action->event->getErrorString());
		log->SetDefaultStyle(wxTextAttr(*wxBLACK));
		log->Thaw();
		scrollToEnd();
	}
}

void RichTextChatLog::doScrollToEnd(){
	log->ShowPosition(log->GetLastPosition());
	log->ScrollLines(10);
}

void RichTextChatLog::writeStatusMessage(const Status & newStatus, const wxString & statusMsg){
	LogStatusMessageAction* action = new LogStatusMessageAction();
	action->status=newStatus;
	action->statusMsg=statusMsg;
	actions.push_back(action);
}

void RichTextChatLog::writeMessage(const wxDateTime & time, Buddy* sender,const wxString & msg, bool in, bool isHistory, const ActionId & id){
	LogMessageAction* action = new LogMessageAction();
	action->time=time;
	action->sender=sender;
	action->msg=msg;
	action->in=in;
	action->isHistory=isHistory;
	action->id=id;
	actions.push_back(action);
}

void RichTextChatLog::markMessage(MessageCallbackEvent event){
	LogMarkMessageAction* action = new LogMarkMessageAction();
	action->event = (MessageCallbackEvent*)event.Clone();
	actions.push_back(action);
}

void RichTextChatLog::scrollToEnd(){
	LogScollToEndAction* action = new LogScollToEndAction();
	actions.push_back(action);
}

wxWindow* RichTextChatLog::getWindow(){
	return log;
}

void RichTextChatLog::writeParsedText(const wxString & text){

	wxString urlExpression = wxT("(?:https*://|www\\.)\\S+\\.\\S+");
	wxString expression = wxT("(");

	expression << smileys->getRegExpString();
	expression << wxT("|") << urlExpression << wxT(")");

	wxRegEx reg(expression,wxRE_ADVANCED|wxRE_ICASE);
	wxRegEx urlReg(urlExpression,wxRE_ADVANCED|wxRE_ICASE);

	const wxChar* toLook = text.GetData();
	size_t lng = text.length();




	while(reg.Matches(toLook,wxRE_NOTBOL|wxRE_NOTEOL,lng)){

		wxString match = reg.GetMatch(toLook, 1);
		size_t mstart, mlng;
	    reg.GetMatch(&mstart,&mlng,1);

	    if(mstart!=0){
		    log->WriteText(wxString(toLook,mstart));
	    }

	    //is url?
	    if(urlReg.Matches(match,wxRE_NOTBOL|wxRE_NOTEOL)){
		    wxRichTextAttr urlStyle;
		    urlStyle.SetTextColour(*wxBLUE);
		    urlStyle.SetFontUnderlined(true);

		    log->BeginStyle(urlStyle);
		    log->BeginURL(match);
		    log->WriteText(match);
		    log->EndURL();
		    log->EndStyle();
	    }else{ //was no url!
			wxBitmap* btm = smileys->getBitmap(match);
	    	if(btm != NULL){
		    	smileyCount++;

		    	if(smileyCount<300){
		    		log->WriteImage(*btm);
		    	}else{
		    		log->WriteText(match);
		    	}
	    	}else{
	    		//was no url and no smiley
		    	log->WriteText(match);
		    }
	    }

	    size_t offset = mstart + mlng;
	    toLook+=offset;
	    lng -= offset;
	}

	if(lng!=0){
		log->WriteText(wxString(toLook,lng));
	}

}

void RichTextChatLog::clear(){
	std::vector<LogAction*>::iterator i(actions.begin());

	for(; i != actions.end(); i++){
		LogAction* action = *i;
		delete action;
	}

	actions.clear();
	log->SetValue(wxEmptyString);
}

}
